[% setvar title Objects : NEXT pseudoclass for method redispatch %]
<div id="archive-notice">
    <h3>This file is part of the Perl 6 Archive</h3>
    <p>To see what is currently happening visit <a href="http://www.perl6.org/">http://www.perl6.org/</a></p>
</div>
<div class='pod'>
<a name='TITLE'></a><h1>TITLE</h1>
<p>Objects : NEXT pseudoclass for method redispatch</p>
<a name='VERSION'></a><h1>VERSION</h1>
<pre>  Maintainer: Damian Conway &lt;<a href='mailto:damian@conway.org'>damian@conway.org</a>&gt;
  Date: 1 Sep 2000
  Last Modified: 18 Sep 2000
  Mailing List: <a href='mailto:perl6-language-objects@perl.org'>perl6-language-objects@perl.org</a>
  Number: 190
  Version: 2
  Status: Frozen</pre>
<a name='ABSTRACT'></a><h1>ABSTRACT</h1>
<p>This RFC proposes a new pseudoclass named <code>NEXT</code>.
This pseudoclass would provide a way of correctly redispatching a method
or an autoloaded method.</p>
<a name='DESCRIPTION'></a><h1>DESCRIPTION</h1>
<p>Perl 5 provides a pseudoclass named <code>SUPER</code> that allows a method to
redispatch a call to the next available method in one of its parent
classes. This redispatch mechanism works by searching for an inherited
method in any of the ancestors of the <i>current</i> package (but not
necessarily the invocant's package). This works well in many cases, but
not when the next most appropriate method is actually in a sibling class
of the current package, rather than in an ancestor.</p>
<p>For example, consider invoking a debugging method named <code>dump_info</code>
on a derived class object:</p>
<pre>        $obj-&gt;dump_info();</pre>
<p>In order to ensure that all the object's ancestral information
was also dumped, its <code>dump_info</code> method might be structured like so:</p>
<pre>        package Derived;
        use base qw(Base1 Base2);

        sub dump_info {
                my ($self) = @_;
                $self-&gt;SUPER::dump_info();
                print $self-&gt;{derived_info};
        }</pre>
<p>The various ancestral classes would then be structured similarly:</p>
<pre>        package Base1;
        use base qw(GrandBase1);

        sub dump_info {
                my ($self) = @_;
                $self-&gt;SUPER::dump_info();
                print $self-&gt;{base1_info};
        }


        package Base2;
        use base qw(GrandBase2 GrandBase3);

        sub dump_info {
                my ($self) = @_;
                $self-&gt;SUPER::dump_info();
                print $self-&gt;{base2_info};
        }

        # etc.</pre>
<p>Unfortunately, this does not result in the derived object's complete
information being dumped, since each call to <code>SUPER::dump_info</code>
will only call a single (left-most) ancestral <code>dump_info</code>. Thus only the
<code>dump_info</code> methods in the left-most inheritance branch will ever
be called.</p>
<p>What is required here is a mechanism to resume the <i>original</i> dispatch
process, rather than initiate a new one from the current point.</p>
<p>It is proposed that Perl 6 provide a new pseudoclass -- <code>NEXT</code> --
to facilitate exactly that.</p>
<p>A method invocation in which the method name is explicitly qualified
with <code>NEXT::</code> (e.g. <code>$self-</code>NEXT::method(@args)&gt;) would cause the
original dispatch that invoked the current method to be restarted and
the next suitable method called.</p>
<p>Another way of thinking of the effect of such a redispatch would be that
it repeats the original dispatch of <code>$self-</code>method(@args)&gt;, but ignores
all dispatch candidates until it has reached (and by-passed) the current
method. Of course, the mechanism wouldn't actually be implemented in
this inefficient manner.</p>
<p>Note that, after the redispatch, control returns to the original method.</p>
<a name='Redispatch of AUTOLOAD methods'></a><h2>Redispatch of <code>AUTOLOAD</code> methods</h2>
<p>The <code>NEXT</code> pseudoclass also solves the problem of how to allow
<code>AUTOLOAD</code> methods to &quot;decline&quot; to handle particular invocations.</p>
<p>For example, with <code>NEXT</code> it is possible to implement an <code>AUTOLOAD</code>
method that only handles method calls of the form <code>get_...</code> and
<code>set_...</code> and is effectively invisible to any other method requests
(which might then trigger other <code>AUTOLOAD</code>s elsewhere in the
object's inheritance tree).</p>
<p>The implementation would look like this:</p>
<pre>        sub AUTOLOAD {
                $AUTOLOAD =~ s/.*:://;
                if ($AUTOLOAD =~ /^get_\w+$/) {
                        # Handle getting...
                }
                elsif ($AUTOLOAD =~ /^set_\w+$/) {
                        # Handle setting...
                }
                else {
                        # Decline to handle,
                        # passing the request on to someone else...
                        shift-&gt;${\&quot;NEXT::$AUTOLOAD&quot;}(@_);
                }
        }</pre>
<p>Note that the same trick could be applied by any method, to selectively
refuse certain invocations, handing them on to some other inherited
method instead. For example:</p>
<pre>	package IO::URL;
	use base 'IO::File';

	sub open {
		my ($self, $filename, @args) = @_;
		if ($filename !~ /^(http|ftp):/) {
			$self-&gt;NEXT::open($filename, @args);
		}
		else {
			# Open URL...
		}
	}</pre>
<a name='MIGRATION ISSUES'></a><h1>MIGRATION ISSUES</h1>
<p>None.</p>
<a name='IMPLEMENTATION'></a><h1>IMPLEMENTATION</h1>
<p>Presumably it would be necessary to cache the dispatch stack until
the dispatched method finishes executing.</p>
<p>Alternatively, implementing the method dispatcher as a coroutine
would make this very easy.</p>
<a name='REFERENCES'></a><h1>REFERENCES</h1>
<p>Conway, <i>Object Oriented Perl</i>, pp. 183-184.</p>
<p>RFC 8: The AUTOLOAD subroutine should be able to decline a request</p>
</div>
